---
slug: /features/programmability
description: "Write workflows in code, not YAML"
---

import Tabs from "@theme/Tabs";
import TabItem from "@theme/TabItem";
import VideoPlayer from '../../src/components/VideoPlayer';

# Programmable Workflows

Dagger provides a specialized container engine for application delivery workflows, enabling you to replace your YAML-based CI/CD workflows with code in your favorite programming language. This allows you to build your delivery workflows in the same language as your application and benefit from your language's existing ecosystem for tooling and best practices.

## Functions

Dagger Functions are the fundamental unit of computing in Dagger. Dagger Functions let you encapsulate common project operations or workflows, such as "pull a container image", "copy a file", and "forward a TCP port", into portable, reusable program code with clear inputs and outputs.

### Example

Here's an example of a Dagger Function that builds and containerizes a Go application:

<Tabs groupId="language" queryString="sdk">
<TabItem value="go" label="Go">
```go file=./snippets/programmability-1/go/main.go
```
</TabItem>
<TabItem value="python" label="Python">
```python file=./snippets/programmability-1/python/main.py
```
</TabItem>
<TabItem value="typescript" label="TypeScript">
```typescript file=./snippets/programmability-1/typescript/index.ts
```
</TabItem>
<TabItem value="php" label="PHP">
```php file=./snippets/programmability-1/php/src/MyModule.php
```
</TabItem>
<TabItem value="java" label="Java">
```java file=./snippets/programmability-1/java/src/main/java/io/dagger/modules/mymodule/MyModule.java
```
</TabItem>
</Tabs>

See it in action:

<VideoPlayer src="/img/current_docs/features/build.webm" alt="Build example" />


## Return types

This Dagger Function returns a "just-in-time container" - a transient artifact generated by stringing together calls to the Dagger API using program code. Dagger is commonly used to produce artifacts like these, including binary files, containers, generated code or documentation, lint or vulnerability scan reports, and so on.

Just-in-time artifacts themselves expose additional functions that allow them to be inspected or processed further. So, for example, if a Dagger Function returns a just-in-time file, you can continue "chaining" operations on it by calling functions exposed by that artifact type, such as exporting it to the host filesystem, modifying it, mounting it into a container, and so on. This feature makes it possible to develop complex delivery pipelines with relatively little effort.

:::tip
Dagger leverages GraphQL's lazy evaluation model to optimize and parallelize query execution for maximum speed and performance.
:::

### Example

Here's an example of calling the same Dagger Function again, but this time chaining an additional operation on the just-in-time container to publish it to a container registry:

<VideoPlayer src="/img/current_docs/features/build-publish.webm" alt="Build and publish example" />

Here's the same Dagger Function again, modified to return the compiled binary as a just-in-time file. The file is then exported to the host via an additional, chained function call:

<Tabs groupId="language" queryString="sdk">
<TabItem value="go" label="Go">
```go file=./snippets/programmability-2/go/main.go
```
</TabItem>
<TabItem value="python" label="Python">
```python file=./snippets/programmability-2/python/main.py
```
</TabItem>
<TabItem value="typescript" label="TypeScript">
```typescript file=./snippets/programmability-2/typescript/index.ts
```
</TabItem>
<TabItem value="php" label="PHP">
```php file=./snippets/programmability-2/php/src/MyModule.php
```
</TabItem>
<TabItem value="java" label="Java">
```java file=./snippets/programmability-2/java/src/main/java/io/dagger/modules/mymodule/MyModule.java
```
</TabItem>
</Tabs>

See it in action:

<VideoPlayer src="/img/current_docs/features/build-export.webm" alt="Build and export example" />
